﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace Nb.Common
{
    public class EnumHelper
    {
        public static IList<DescModel> GetDescModels<T>()
        {
            var descModels = new List<DescModel>();

            CheckType<T>();
            var type = typeof (T);
            var values = Enum.GetValues(type);
            foreach (var item in values)
            {
                var descModel = new DescModel();
                descModel.StringValue = Enum.GetName(type, item);
                descModel.IntValue = (int)item;

                Enum theEnum = (Enum) item;
                var description = GetDescription(theEnum);
                if (description != null)
                {
                    descModel.Description = description;
                }

                descModels.Add(descModel);
            }

            return descModels;
        }

        /// <summary>
        /// 输出所有值的数组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static int[] ToArray<T>()
        {
            CheckType<T>();
            var values = (int[])Enum.GetValues(typeof(T));
            return values;
        }

        public static IList<T> ToList<T>()
        {
            CheckType<T>();
            var values = Enum.GetValues(typeof(T));
            return values as List<T>;
        }
        
        /// <summary>
        /// 获取枚举项的Attribute
        /// </summary>
        /// <typeparam name="T">自定义的Attribute</typeparam>
        /// <param name="source">枚举</param>
        /// <returns>返回枚举,否则返回null</returns>
        public static T GetCustomAttribute<T>(Enum source) where T : Attribute
        {
            Type sourceType = source.GetType();
            var fieldInfo = sourceType.GetField(source.ToString());
            if (fieldInfo!=null)
            {
                var customAttributes = (T[])fieldInfo.GetCustomAttributes(typeof(T), false);
                if (customAttributes.Any())
                {
                    return customAttributes.First();
                }
            }
            return default(T);
        }

        /// <summary>
        ///获取DescriptionAttribute描述
        /// </summary>
        /// <param name="source">枚举</param>
        /// <returns>有description标记，返回标记描述，否则返回null</returns>
        public static string GetDescription(Enum source)
        {
            var attr = GetCustomAttribute<DescriptionAttribute>(source);
            if (attr == null)
            {
                return null;
            }
            return attr.Description;
        }
        
        public static T FromInt<T>(int value)
        {
            return (T)Enum.ToObject(typeof(T), value);
        }

        public static T FromString<T>(string value)
        {
            return (T)Enum.Parse(typeof(T), value);
        }

        //8421异或逻辑
        public static int BulidCode<T>(IList<T> items)
        {
            CheckType<T>();
            CheckParams(items);

            const int ret = 0;
            return items == null ?
                ret :
                items.Aggregate(ret, (current, item) => current | Convert.ToInt32((item as Enum)));
        }
        public static IList<T> ParseCode<T>(int code)
        {
            CheckType<T>();
            var ret = (from T item in Enum.GetValues(typeof(T))
                       let i = code ^ (code & Convert.ToInt32((item as Enum)))
                       where i != code
                       select item).ToList();
            return ret;
        }
        
        private static void CheckType<T>()
        {
            //运行时检查是否是枚举类型
            if (!typeof(T).IsEnum)
                throw new ArgumentException("仅支持枚举类型！");
        }
        private static void CheckParams<T>(IList<T> items)
        {
            if (items == null || items.Count == 0)
            {
                throw new ArgumentException("必须至少指定一个合法的参数");
            }
        }
    }

    public static class EnumExtension
    {
        public static string GetDescription(this Enum source)
        {
            var attr = EnumHelper.GetCustomAttribute<DescriptionAttribute>(source);
            if (attr == null)
            {
                return null;
            }
            return attr.Description;
        }
    }

    public class DescModel
	{
        public int IntValue { get; set; }
        public string StringValue { get; set; }
        public string Description { get; set; }
	}
}